import { SubjectComponent } from "../core/subject";
import { VectorHelper } from "../core/utils";


const { executeInEditMode, ccclass, property } = cc._decorator;

export enum DragListType {
    Horizontal = 1,
    Vertical,
};
@ccclass
@executeInEditMode
export default class DragList extends SubjectComponent {
    @property({
        type: cc.Enum(DragListType)
    })
    type: DragListType = DragListType.Vertical;

    lastDelta = 0;
    draging = false;
    @property(cc.Node)
    root: cc.Node = null;
    @property({
        serializable: true
    })
    _enabledTouch = false;
    @property
    get enabledTouch() {
        return this._enabledTouch;
    }
    set enabledTouch(val) {
        this._enabledTouch = val;
        this.resetTouch();
    }
    @property
    size = 400;

    @property
    curInd = 0;

    onLoad() {
        this.resetTouch();
    }
    protected start(): void {
        this.select(this.curInd);
    }

    autoSwitch(time: number) {
        cc.Tween.stopAllByTarget(this);
        if (time !== 0) {
            cc.tween(this).repeatForever(cc.tween().delay(time).call(() => {
                let ind = this.curInd + 1;
                if (ind >= this.root.childrenCount) {
                    ind = 0;
                }
                this.select(ind);
            })).start();
        }
    }
    resetTouch() {
        if (this._enabledTouch) {
            this.node.on(cc.Node.EventType.TOUCH_START, this.onTouchStart, this);
            this.node.on(cc.Node.EventType.TOUCH_MOVE, this.onTouchMove, this);
            this.node.on(cc.Node.EventType.TOUCH_CANCEL, this.onTouchEnd, this);
            this.node.on(cc.Node.EventType.TOUCH_END, this.onTouchEnd, this);
        }
        else {
            this.node.off(cc.Node.EventType.TOUCH_START, this.onTouchStart, this);
            this.node.off(cc.Node.EventType.TOUCH_MOVE, this.onTouchMove, this);
            this.node.off(cc.Node.EventType.TOUCH_CANCEL, this.onTouchEnd, this);
            this.node.off(cc.Node.EventType.TOUCH_END, this.onTouchEnd, this);
        }
    }
    _touchDv = 0;
    _touchDelta = cc.v2();
    onTouchStart(evt: cc.Event.EventTouch) {
        this._touchDv = 0;
        this._touchDelta = cc.v2();
    }
    onTouchMove(evt: cc.Event.EventTouch) {
        let delta = evt.getDelta();
        this._touchDv += delta.mag();
        this._touchDelta.addSelf(delta);
        this.drag(delta);
    }
    onTouchEnd(evt: cc.Event.EventTouch) {
        if (this._touchDv < 30) {
            this.drop();
        }
        else {
            let np = this._touchDelta;
            let touchDt = 0;
            if (this.type === DragListType.Horizontal) {
                touchDt = np.x;
            }
            else {
                touchDt = -np.y;
            }
            if (touchDt < 0) {
                this.next();
            }
            else {
                this.prev();
            }
        }
        this._touchDv = 0;
        this._touchDelta = cc.v2();
    }

    drag(delta: cc.Vec2) {
        cc.Tween.stopAllByTag(2);
        this.root.children.forEach(child => {
            if (this.type === DragListType.Vertical) {
                child.y += delta.y;
            }
            else {
                child.x += delta.x;
            }
        });

        if (this.type === DragListType.Vertical) {
            this.lastDelta = delta.y;
        }
        else {
            this.lastDelta = delta.x;
        }
        this.draging = true;
    }

    drop() {
        this.draging = false;
        // this.rollBack();
        if (this.lastDelta == 0) {
            this.rollBack();
        }
    }
    rollBack() {
        //计算最近的一个NODE 偏离。
        let nodeInd = VectorHelper.getNearestNodeIndex(cc.v2(), this.root.children);
        this.select(nodeInd);
    }

    rollToNode(ind: number) {
        let node = this.root.children[ind];
        if (this.type === DragListType.Vertical) {
            let delta = node.y;
            this.root.children.forEach(child => {
                cc.Tween.stopAllByTarget(child);
                cc.tween(child)
                    .tag(2)
                    .by(0.18, { y: -delta })
                    .start();
            });
        }
        else {
            let delta = node.x;
            this.root.children.forEach(child => {
                cc.Tween.stopAllByTarget(child);
                cc.tween(child)
                    .tag(2)
                    .by(0.18, { x: -delta })
                    .start();
            });
        }
    }

    select(ind: number) {
        this.curInd = ind;
        this.rollToNode(ind);
        this.emit("select-changed", ind);
    }

    next() {
        let ind = this.curInd;
        ind++;
        if (ind >= this.root.childrenCount) {
            ind = 0;
        }
        this.select(ind);
    }
    prev() {
        let ind = this.curInd;
        ind--;
        if (ind < 0) {
            ind = this.root.childrenCount - 1;
        }
        this.select(ind);
    }


    protected lateUpdate(dt: number): void {
        for (let i = 0; i < this.root.childrenCount; i++) {
            let child = this.root.children[i];

            if (this.type === DragListType.Vertical) {
                let minPer = 1 - Math.abs(child.y / (this.size / 2));

                if (!this.draging && this.lastDelta != 0) {
                    child.y += this.lastDelta;
                }

                if (child.y < -this.size / 2) {
                    let delta = child.y + this.size / 2;
                    child.y = this.size / 2 + delta;
                }
                else if (child.y > this.size / 2) {
                    let delta = child.y - this.size / 2;
                    child.y = -this.size / 2 + delta;
                }
            }
            else {
                let minPer = 1 - Math.abs(child.x / (this.size / 2));

                if (!this.draging && this.lastDelta != 0) {
                    child.x += this.lastDelta;
                }

                if (child.x < -this.size / 2) {
                    let delta = child.x + this.size / 2;
                    child.x = this.size / 2 + delta;
                }
                else if (child.x > this.size / 2) {
                    let delta = child.x - this.size / 2;
                    child.x = -this.size / 2 + delta;
                }
            }

        }

        if (this.draging) {
            return;
        }
        if (this.lastDelta != 0) {
            this.lastDelta *= 0.96;
            if (this.lastDelta <= 2) {
                this.lastDelta = 0;
                this.rollBack();
            }
        }

    }
};